Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Commit b528c127277839175e77c8b2de312769937d4f47


Parents : 1ae0745
Author : Sudo-Ivan <ivan@quad4.io>
Signature : Signature validation error
Date : 2026-03-09T12:10:26-05:00

Fix partial page loading with fields and auto-refresh

NomadNet partials can include field data in their syntax.
- PARTIAL_LINE_REGEX updated to capture optional fields group
- WebSocket handler allows partial responses when callback registered
- Strip field_ prefix before send to avoid double-prefixing
- Partial DOM updates via innerHTML instead of Vue reactivity

Co-Authored-By: torlando-tech <torlando-tech@users.noreply.github.com>

Changes
Diff

diff --git a/meshchatx/src/frontend/components/nomadnetwork/NomadNetworkPage.vue b/meshchatx/src/frontend/components/nomadnetwork/NomadNetworkPage.vue
index 6e472101..8c754c71 100644
--- a/meshchatx/src/frontend/components/nomadnetwork/NomadNetworkPage.vue
+++ b/meshchatx/src/frontend/components/nomadnetwork/NomadNetworkPage.vue
@@ -583,8 +583,15 @@ export default {
}
// ignore response if it's for a different page than currently requested/viewed
+ // but allow responses for partial pages (they have registered callbacks)
if (this.nodePagePath && responsePagePath !== this.nodePagePath) {
- return;
+ const callbackKey = this.getNomadnetPageDownloadCallbackKey(
+ nomadnetPageDownload.destination_hash,
+ nomadnetPageDownload.page_path
+ );
+ if (!this.nomadnetPageDownloadCallbacks[callbackKey]) {
+ return;
+ }
}
// handle started status
@@ -996,18 +1003,32 @@ export default {
const refreshByKey = {};
const needLoad = new Set();
+ const fieldsByKey = {};
placeholders.forEach((el) => {
const id = el.getAttribute("data-partial-id");
const dest = el.getAttribute("data-dest");
const path = el.getAttribute("data-path");
const refreshAttr = el.getAttribute("data-refresh");
const refresh = refreshAttr ? parseInt(refreshAttr, 10) : null;
+ const fieldsStr = el.getAttribute("data-fields");
const key = dest + ":" + path;
if (!idsByKey[key]) idsByKey[key] = [];
idsByKey[key].push({ id, refresh });
if (refresh != null && refresh > 0) {
refreshByKey[key] = Math.min(refreshByKey[key] ?? Infinity, refresh);
}
+ if (fieldsStr && !fieldsByKey[key]) {
+ const fieldData = {};
+ for (const part of fieldsStr.split("|")) {
+ const eq = part.indexOf("=");
+ if (eq > 0) {
+ let name = part.slice(0, eq);
+ if (name.startsWith("field_")) name = name.slice(6);
+ fieldData[name] = part.slice(eq + 1);
+ }
+ }
+ fieldsByKey[key] = fieldData;
+ }
if (!this.pagePartials[id]) needLoad.add(key);
});
@@ -1015,33 +1036,40 @@ export default {
this.partialRefreshByKey = refreshByKey;
const muParser = new MicronParser();
+ const updatePartialDom = (html, ids) => {
+ const container = this.$el.querySelector(".nodeContainer");
+ if (!container) return;
+ for (const { id } of ids) {
+ const el = container.querySelector(`[data-partial-id="${id}"]`);
+ if (el) {
+ el.innerHTML = html;
+ }
+ }
+ };
needLoad.forEach((key) => {
const colon = key.indexOf(":");
const dest = key.slice(0, colon);
const path = colon >= 0 ? key.slice(colon + 1) : "";
+ const fields = fieldsByKey[key] || [];
this.downloadNomadNetPage(
dest,
path,
- [],
+ fields,
(pageContent) => {
const html = muParser.convertMicronToHtml(pageContent);
const ids = this.partialIdsByKey[key];
if (ids) {
- const next = { ...this.pagePartials };
- ids.forEach(({ id }) => (next[id] = html));
- this.pagePartials = next;
+ updatePartialDom(html, ids);
}
const refreshSec = this.partialRefreshByKey[key];
if (refreshSec != null && refreshSec > 0) {
const scheduleRefresh = () => {
this.partialRefreshTimers[key] = setTimeout(() => {
- this.downloadNomadNetPage(dest, path, [], (content) => {
+ this.downloadNomadNetPage(dest, path, fields, (content) => {
const h = muParser.convertMicronToHtml(content);
const idList = this.partialIdsByKey[key];
if (idList) {
- const next = { ...this.pagePartials };
- idList.forEach(({ id }) => (next[id] = h));
- this.pagePartials = next;
+ updatePartialDom(h, idList);
}
scheduleRefresh();
});

diff --git a/meshchatx/src/frontend/js/MicronParser.js b/meshchatx/src/frontend/js/MicronParser.js
index 39664efa..4bb41226 100644
--- a/meshchatx/src/frontend/js/MicronParser.js
+++ b/meshchatx/src/frontend/js/MicronParser.js
@@ -144,11 +144,14 @@ class MicronParser {
}
/**
- * Match partial include line: `{dest32hex:/path.mu}` or `{dest32hex:/path.mu`seconds}`.
+ * Match partial include line:
+ * `{dest32hex:/path.mu}`
+ * `{dest32hex:/path.mu`seconds}`
+ * `{dest32hex:/path.mu`seconds`fields}`
*/
static get PARTIAL_LINE_REGEX() {
// eslint-disable-next-line security/detect-unsafe-regex -- fixed pattern, bounded input (single line)
- return /^`\{([a-f0-9]{32}):([^`}]*)(?:`(\d+))?\}$/;
+ return /^`\{([a-f0-9]{32}):([^`}]*)(?:`(\d+)(?:`([^}]*))?)?\}$/;
}
convertMicronToHtml(markup, partialContents = {}) {
@@ -286,6 +289,7 @@ class MicronParser {
const dest = partialMatch[1];
const path = partialMatch[2];
const refresh = partialMatch[3] ? parseInt(partialMatch[3], 10) : null;
+ const fields = partialMatch[4] || null;
const id = "partial-" + state.partialIndex++;
const div = document.createElement("div");
div.className = "mu-partial";
@@ -295,6 +299,9 @@ class MicronParser {
if (refresh != null && refresh > 0) {
div.setAttribute("data-refresh", String(refresh));
}
+ if (fields) {
+ div.setAttribute("data-fields", fields);
+ }
div.textContent = "Loading...";
return [div];
}


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────